#if USE_UNI_LUA
using LuaAPI = UniLua.Lua;
using RealStatePtr = UniLua.ILuaState;
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
#else
using LuaAPI = XLua.LuaDLL.Lua;
using RealStatePtr = System.IntPtr;
using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
#endif

using System;
using System.Collections.Generic;

namespace XLua {

    /// <summary>
    ///     Add Invoke interface for XLua.LuaFunction.
    /// </summary>
    public partial class LuaFunction {

        /// <summary>
        ///     Call LUA function without returns.
        /// </summary>
        /// <param name="args">Parameters for invoke this call.</param>
        public void Invoke(params object[] args) {
#if THREAD_SAFE || HOTFIX_ENABLE
            lock (luaEnv.luaEnvLock) {
#endif
            var L = luaEnv.L;
            var translator = luaEnv.translator;
            int oldTop = LuaAPI.lua_gettop(L);
            int errFunc = LuaAPI.load_error_func(L, luaEnv.errorFuncRef);
            int error = 0;

            LuaAPI.lua_getref(L, luaReference);

            if (args == null) {
                error = LuaAPI.lua_pcall(L, 0, 0, errFunc);
            } else {
                for (int i = 0; i < args.Length; ++i) {
                    translator.PushAny(L, args[i]);
                }

                error = LuaAPI.lua_pcall(L, args.Length, 0, errFunc);
            }

            if (error != 0) luaEnv.ThrowExceptionFromError(oldTop);
            LuaAPI.lua_settop(L, oldTop);
#if THREAD_SAFE || HOTFIX_ENABLE
            }
#endif
        }

        /// <summary>
        ///     Call LUA function and get result.
        /// </summary>
        /// <typeparam name="T">Result type.</typeparam>
        /// <param name="args">Parameters to invoke this call.</param>
        /// <returns>Result.</returns>
        public T Invoke<T>(params object[] args) {
#if THREAD_SAFE || HOTFIX_ENABLE
            lock (luaEnv.luaEnvLock) {
#endif
            var L = luaEnv.L;
            var translator = luaEnv.translator;
            int oldTop = LuaAPI.lua_gettop(L);
            int errFunc = LuaAPI.load_error_func(L, luaEnv.errorFuncRef);
            int error = 0;

            LuaAPI.lua_getref(L, luaReference);

            if (args == null) {
                error = LuaAPI.lua_pcall(L, 0, 1, errFunc);
            } else {
                for (int i = 0; i < args.Length; ++i) {
                    translator.PushAny(L, args[i]);
                }

                error = LuaAPI.lua_pcall(L, args.Length, 1, errFunc);
            }

            if (error != 0) luaEnv.ThrowExceptionFromError(oldTop);

            T ret;
            try {
                translator.Get(L, -1, out ret);
            } catch (Exception e) {
                throw e;
            } finally {
                LuaAPI.lua_settop(L, oldTop);
            }

            return ret;
#if THREAD_SAFE || HOTFIX_ENABLE
            }
#endif
        }
    }


}
